//
//  CMObjectParser.m
//  Perilla
//
//  Created by Martin Schiøth Dyrby on 10/18/12.
//  Copyright (c) 2012 Martin Schiøth Dyrby. All rights reserved.
//

#import "CMObjectParser.h"
#import "CMAS3Property.h"

static NSSet *accessorKeys;
static NSSet *childKeys;
static NSSet *numericTypes;
static NSSet *selectTypes;
static NSSet *stringTypes;
static NSSet *boolTypes;
static NSSet *methodKeys;
static NSSet *blackList;
static CMAS3Property* currentMethod;
static NSString* currentMethodName;

@interface CMObjectParser (PrivateAPI)

- (void)logError:(NSString *)msg;
- (void)logInfo:(NSString *)msg;
- (void)logMessage:(NSString *)msg;
- (CMAS3Property*) newPropertyWithName: (NSString *)name
                               andType: (NSString *)type
                           andViewType: (NSString *)viewType;

@end

@implementation CMObjectParser

@synthesize items;
@synthesize children;
@synthesize methods;
@synthesize declared;
@synthesize inherited;
@synthesize path;

+ (void)initialize
{
    if (!accessorKeys) {
        accessorKeys = [[NSSet alloc] initWithObjects: @"accessor", @"variable" ,nil];
    }
    if (!childKeys) {
        childKeys = [[NSSet alloc] initWithObjects: @"child" ,nil];
    }
    if (!numericTypes) {
        numericTypes = [[NSSet alloc] initWithObjects: @"int", @"uint", @"Number", nil];
    }
    
    if(!selectTypes) {
        selectTypes = [[NSSet alloc] initWithObjects: @"blendMode", nil];
    }
    
	if (!stringTypes) {
        stringTypes = [[NSSet alloc] initWithObjects: @"String", nil];
    }
	
	if (!boolTypes) {
        boolTypes = [[NSSet alloc] initWithObjects: @"Boolean", nil];
    }
	
	if (!methodKeys) {
		methodKeys = [[NSSet alloc] initWithObjects: @"method", nil];
	}
	
    if(!blackList) {
        blackList = [[NSSet alloc] initWithObjects: @"willTrigger", @"hasEventListener", @"getChildByName", @"contextMenu",@"getChildAt",nil];
    }
	
}



- (BOOL)parseData:(NSData *)d
{
    // Create a new, empty itemArray
    items = [[NSMutableSet alloc] init];
	children = [[NSMutableArray alloc] init];
	methods = [[NSMutableArray alloc] init];
	declared = [[NSMutableArray alloc] init];
	inherited = [[NSMutableArray alloc] init];
	
    // Create a parser
    NSXMLParser *parser = [[NSXMLParser alloc] initWithData:d];
    [parser setDelegate:self];
	
    // Do the parse
    [parser parse];
	
    return YES;
}


- (NSSet *)parseItems
{
	for (int c = 0; c < [children count]; c++) {
		[items addObject: [children objectAtIndex: c]];
	}
	for (int d = 0; d < [declared count]; d++) {
		[items addObject: [declared objectAtIndex: d]];
	}
	for (int i = 0; i < [inherited count]; i++) {
		[items addObject: [inherited objectAtIndex: i]];
	}
	for (int m = 0; m < [methods count]; m++) {
		[items addObject: [methods objectAtIndex: m]];
	}
    
    return items;
}

- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI
 qualifiedName:(NSString *)qualifiedName
	attributes:(NSDictionary *)attributeDict {
	
	BOOL insert = NO;
    NSString* name = nil;
    NSString* type = nil;
    if ([accessorKeys containsObject:elementName]) {
        
        CMAS3Property* property = nil;

        name = [attributeDict objectForKey:@"name"];
        type = [attributeDict objectForKey:@"type"];
        
		NSString* declaredBy = [attributeDict objectForKey:@"declaredBy"];
		
		if([elementName isEqualToString: @"accessor"]) {
			NSString* access = [attributeDict objectForKey:@"access"];
            
			insert = [access isEqualToString: @"readwrite"];
            
            if([selectTypes containsObject:property.name]) {
                property = [self newPropertyWithName: name andType: type andViewType:@"select"];
            } else if([numericTypes containsObject:property.type]) {
                property = [self newPropertyWithName: name andType: type andViewType:@"number"];
			} else if([stringTypes containsObject:property.type]) {
                property = [self newPropertyWithName: name andType: type andViewType:@"string"];
			} else if([boolTypes containsObject:property.type]) {
                property = [self newPropertyWithName: name andType: type andViewType:@"boolean"];
			} else{
                property = [self newPropertyWithName: name andType: type andViewType:@"complex"];
			}
		} else{
			insert = YES;
			
			if([numericTypes containsObject:property.type]) {
                property = [self newPropertyWithName: name andType: type andViewType:@"number"];
			} else if([stringTypes containsObject:property.type]) {
                property = [self newPropertyWithName: name andType: type andViewType:@"string"];
			} else if([boolTypes containsObject:property.type]) {
                property = [self newPropertyWithName: name andType: type andViewType:@"boolean"];
			} else {
                property = [self newPropertyWithName: name andType: type andViewType:@"complex"];
			}
		}
        
		if(insert){
            if(![blackList containsObject:property.name]) {
                if(declaredBy != nil) {
                    if(property != nil) [inherited addObject:property];
                } else {
                    if(property != nil) [declared addObject:property];
                }
            }
		}
        
    } else if([childKeys containsObject:elementName]) {
        

		name = [attributeDict objectForKey:@"name"];
        
		type = [attributeDict objectForKey:@"type"];
        
        CMAS3Property* child = [self newPropertyWithName: name andType: type andViewType:@"complex"];
        		
        [children addObject:child];
	} else if ([elementName isEqualToString: @"type"]) {
		path = [attributeDict objectForKey:@"path"];
	} else if([methodKeys containsObject:elementName]) {
		currentMethodName = [attributeDict objectForKey:@"name"];
	} else if ([elementName isEqualToString:@"parameter"]) {
		if([[attributeDict objectForKey:@"index"] isEqualToString: @"1"]) {
            
            type = [attributeDict objectForKey:@"type"];
            if([numericTypes containsObject:type]) {
                currentMethod = [self newPropertyWithName: name andType: type andViewType:@"numeric"];
            } else if([stringTypes containsObject:type]) {
                currentMethod = [self newPropertyWithName: name andType: type andViewType:@"string"];
            } else if([boolTypes containsObject:type]) {
                currentMethod = [self newPropertyWithName: name andType: type andViewType:@"boolean"];
            } else {
                return;
            }
            
            [currentMethod setName: currentMethodName];
            [currentMethod setType: type];
            [currentMethod setMethod: YES];
            
		} else {
			currentMethod = nil;
		}
	}
}

- (void)parser:(NSXMLParser *)parser
 didEndElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI
 qualifiedName:(NSString *)qName
{
    if([blackList containsObject:currentMethod.name]) {
        currentMethod = nil;
        return;
    }
	if([methodKeys containsObject:elementName] && currentMethod != nil) {
		[methods addObject:currentMethod];
		currentMethod = nil;
	}
}

- (void)parser:(NSXMLParser *)parser
foundCharacters:(NSString *)string
{
    
}

- (CMAS3Property *) newPropertyWithName: (NSString *)name andType: (NSString *)type andViewType: (NSString *)viewType {
    CMAS3Property* property = [[CMAS3Property alloc] init];
    property.name = name;
    property.type = type;
    property.viewtype = viewType;
    
    return property;
}

@end
